package com.wlyuan.open.scanner.utils;

import lombok.var;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
public class StreamUtils {

    /**
     * 转换
     *
     * @param collection
     * @param formatter
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> convert(Collection<T> collection, Function<T, R> formatter) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyList();
        }
        return collection.stream().map(formatter).collect(Collectors.toList());
    }

    /**
     * 可选返回字段函数式分组
     *
     * @param collection      列表
     * @param classifier      分组字段选择
     * @param mappingFunction 返回字段
     * @param <T>             输入类型
     * @param <K>             key类型
     * @param <U>             最后返回的元素类型
     * @return 最后返回Map<K, List < U>
     */
    public static <T, K, U> Map<K, List<U>> groupBy(Collection<T> collection, Function<? super T, ? extends K> classifier, Function<? super T, ? extends U> mappingFunction) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyMap();
        }
        return collection.stream().collect(Collectors.groupingBy(classifier, Collectors.mapping(mappingFunction, Collectors.toList())));
    }

    /**
     * 可选返回字段函数式分组 + 排序字段选择
     *
     * @param collection      列表
     * @param classifier      分组字段选择
     * @param mappingFunction 返回字段
     * @param keySelect       排序字段选择
     * @param desc            是否降序
     * @param <T>             输入类型
     * @param <K>             key类型
     * @param <U>             最后返回的元素类型
     * @return 最后返回Map<K, List < U>
     */
    public static <T, K, U, C extends Comparable<C>> Map<K, List<U>> groupBy(List<T> collection, Function<? super T, ? extends K> classifier,
                                                                             Function<? super T, ? extends U> mappingFunction, boolean desc,
                                                                             Function<? super T, ? extends C> keySelect) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyMap();
        }
        sortList(collection, desc, keySelect);
        return collection.stream().collect(Collectors.groupingBy(classifier, Collectors.mapping(mappingFunction, Collectors.toList())));
    }

    /**
     * 简单分组
     *
     * @param collection 集合
     * @param classifier 分组字段选择函数
     * @param <T>        输入类型
     * @param <K>        Key的类型
     * @return 最后返回Map<K, List < T>
     */
    public static <T, K> Map<K, List<T>> groupBy(Collection<T> collection, Function<? super T, ? extends K> classifier) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyMap();
        }
        return collection.stream().filter(obj -> classifier != null).collect(Collectors.groupingBy(classifier, LinkedHashMap::new, Collectors.toList()));
    }

    /**
     * 集合根据指定的Key规则进行分组求最大值
     *
     * @param collection  集合对象
     * @param keyMapper   分组Key的映射规则
     * @param valueMapper value映射规则
     * @param comparator  集合合并的比较器
     * @return Map<K, V>
     */
    public static <K, T, V> Map<K, V> maxByGroup(Collection<T> collection, Function<T, K> keyMapper, Function<T, V> valueMapper, Comparator<V> comparator) {
        return merge(collection, keyMapper, valueMapper, BinaryOperator.maxBy(comparator));
    }

    /**
     * 集合分组后求最大值单个对象
     *
     * @param collection 集合对象
     * @param keyMapper  分组key的映射规则
     * @param comparator 集合合并的比较器
     * @param <K>
     * @param <E>
     * @return
     */
    public static <K, T> Map<K, T> maxByGroup(Collection<T> collection, Function<T, K> keyMapper, Comparator<T> comparator) {
        return maxByGroup(collection, keyMapper, Function.identity(), comparator);
    }

    /**
     * 集合分组后求最最小值单个对象
     *
     * @param collection 集合对象
     * @param keyMapper  分组key的映射规则
     * @param comparator 集合合并的比较器
     * @param <K>
     * @param <T>
     * @return
     */
    public static <K, T> Map<K, T> minByGroup(Collection<T> collection, Function<T, K> keyMapper, Comparator<T> comparator) {
        return merge(collection, keyMapper, Function.identity(), BinaryOperator.minBy(comparator));
    }

    /**
     * 分组取大值集合
     *
     * @param collection
     * @param keyMapper
     * @param comparator
     * @param <T>
     * @return
     */
    public static <K, T> List<T> maxByGroupValues(Collection<T> collection, Function<T, K> keyMapper, Comparator<T> comparator) {
        var map = merge(collection, keyMapper, Function.identity(), BinaryOperator.maxBy(comparator));
        if (CollectionUtils.isEmpty(map)) {
            return Collections.emptyList();
        }
        return map.values().stream().distinct().collect(Collectors.toList());
    }

    /**
     * 集合根据指定的Key规则进行分组合并
     *
     * @param collection     集合对象
     * @param keyMapper      分组Key的映射规则
     * @param valueMapper    value映射规则
     * @param binaryOperator 自定义集合合并的规则
     * @param <K>            Key的泛型
     * @param <T>            集合元素类型的泛型
     * @param <V>            最终输出类型的泛型
     * @return Map<K, V>
     */
    public static <K, T, V> Map<K, V> merge(Collection<T> collection, Function<T, K> keyMapper, Function<T, V> valueMapper, BinaryOperator<V> binaryOperator) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyMap();
        }
        return collection.stream().filter(obj -> keyMapper != null).collect(Collectors.toMap(keyMapper, valueMapper, binaryOperator, LinkedHashMap::new));
    }

    /**
     * 集合转换为Map,存在相同的key，覆盖前面的
     *
     * @param collection  集合对象
     * @param keyMapper   Key的映射规则
     * @param valueMapper value映射规则
     * @param <K>         Key的泛型
     * @param <T>         集合元素类型的泛型
     * @param <V>         最终输出类型的泛型
     * @return Map<K, V>
     */
    public static <K, T, V> Map<K, V> toMap(Collection<T> collection, Function<T, K> keyMapper, Function<T, V> valueMapper) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyMap();
        }
        return collection.stream().collect(Collectors.toMap(keyMapper, valueMapper, (k1, k2) -> k2, LinkedHashMap::new));
    }

    /**
     * 集合转map
     *
     * @param collection
     * @param keyMapper
     * @param <K>
     * @param <T>
     * @return
     */
    public static <K, T> Map<K, T> toMap(Collection<T> collection, Function<T, K> keyMapper) {
        return toMap(collection, keyMapper, Function.identity());
    }

    /**
     * 集合转换为List
     *
     * @param collection  集合对象
     * @param valueMapper value映射规则
     * @param <T>         集合元素类型的泛型
     * @param <V>         最终输出类型的泛型
     * @return List<V>
     */
    public static <T, V> List<V> mapList(Collection<T> collection, Function<T, V> valueMapper) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyList();
        }
        return collection.stream().filter(obj -> valueMapper != null).map(valueMapper).distinct().collect(Collectors.toList());
    }

    /**
     * 按特定规则筛选集合元素，返回List，过滤输入集合的null对象
     *
     * @param <T>        对象类型
     * @param collection 对象集合
     * @param predicate  筛选条件
     * @return
     */
    public static <T> List<T> filter(Collection<T> collection, Predicate<T> predicate) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyList();
        }
        return collection.stream().filter(Objects::nonNull).filter(predicate).collect(Collectors.toList());
    }

    /**
     * 集合去重
     *
     * @param collection 集合
     * @param comparator 去重
     * @param max        倒序，取最大的
     * @param <T>
     * @return
     */
    public static <T> List<T> distinct(Collection<T> collection, Comparator<T> comparator, boolean max) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyList();
        }
        if (max) {
            Collections.reverse(collection.stream().collect(Collectors.toList()));
        }
        return collection.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(comparator)), ArrayList::new));
    }

    /**
     * 基本排序操作, 这里约定了排序字段的选择必须是实现了Comparable接口的.
     *
     * @param list      集合
     * @param desc      是否降序
     * @param keySelect 排序字段选择函数
     * @param <T>       输入类型
     */
    public static <T, U extends Comparable<U>> void sortList(List<T> list, boolean desc, Function<? super T, ? extends U> keySelect) {
        // 这里如果是降序的话, 就将List进行反转
        if (desc) {
            list.sort(Comparator.comparing(keySelect));
            Collections.reverse(list);
        } else {
            list.sort(Comparator.comparing(keySelect));
        }
    }

    /**
     * 计算综合
     *
     * @param collection 集合
     * @param keySelect  字段选择, 不定长参数, 可以选择多个字段进行合并
     * @param <T>
     * @return
     */
    public static <T> Integer sum(Collection<T> collection, Function<? super T, ? extends Number>... keySelect) {
        if (CollectionUtils.isEmpty(collection)) {
            return 0;
        }
        Integer sum = 0;
        for (Function<? super T, ? extends Number> keyFunction : keySelect) {
            sum += collection.stream().mapToInt(s -> keyFunction.apply(s).intValue()).sum();
        }
        return sum;
    }

    /**
     * 集合元素求和
     *
     * @param collection     集合对象
     * @param keyMapper      需要求和的属性映射
     * @param binaryOperator 函数式接口，取两个值并产生一个新值
     * @param defaultResult  默认值或初始值。
     * @return U
     */
    public static <T, U> U sum(Collection<T> collection, Function<T, U> keyMapper, BinaryOperator<U> binaryOperator, U defaultResult) {
        if (CollectionUtils.isEmpty(collection)) {
            return defaultResult;
        }
        return collection.stream().map(keyMapper).reduce(defaultResult, binaryOperator);
    }

    /**
     * 取最小
     *
     * @param collection
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> T min(Collection<T> collection, Comparator<T> comparator) {
        return collection.stream().min(comparator).orElse(null);
    }

    /**
     * 取最大
     *
     * @param collection
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> T max(Collection<T> collection, Comparator<T> comparator) {
        return collection.stream().max(comparator).orElse(null);
    }
}
